﻿using OmniKits.Windows.Behaviors;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;

namespace OmniKits.Windows.Design
{
    public class DesignAdorner : Adorner
    {
        private static readonly DependencyProperty DragMoveBehaviorProperty = DependencyProperty.RegisterAttached("DragMoveBehavior", typeof(DragMoveBehavior), typeof(DesignAdorner), new PropertyMetadata
        {
            PropertyChangedCallback = (d, e) =>
            {
                var old = e.OldValue as DragMoveBehavior;
                if (old != null)
                    old.Detach();
                var @new = e.NewValue as DragMoveBehavior;
                if (@new != null)
                    @new.Attach(d);
            },
        });

        private static readonly DependencyProperty DesignAdornerProperty = DependencyProperty.RegisterAttached("DesignAdorner", typeof(DesignAdorner), typeof(DesignAdorner), new PropertyMetadata
        {
            PropertyChangedCallback = (d, e) =>
            {
                var old = e.OldValue as DesignAdorner;
                if (old != null)
                    old.SetDesignTarget(null);
                var @new = e.NewValue as DesignAdorner;
                if (@new != null)
                    @new.SetDesignTarget(d as UIElement);
            },
        });

        public static readonly DependencyProperty IsDesignModeProperty = DependencyProperty.RegisterAttached("IsDesignMode", typeof(bool), typeof(DesignAdorner), new PropertyMetadata
        {
            PropertyChangedCallback = (d, e) =>
            {
                var da = d.GetValue(DesignAdornerProperty) as DesignAdorner;
                var dmb = d.GetValue(DragMoveBehaviorProperty) as DragMoveBehavior;
                if ((bool)e.NewValue)
                {
                    if (da == null)
                        d.SetValue(DesignAdornerProperty, new DesignAdorner(d as UIElement));
                    if (dmb == null)
                        d.SetValue(DragMoveBehaviorProperty, new DragMoveBehavior());
                }
                else
                {
                    if (da != null)
                        d.SetValue(DesignAdornerProperty, null);
                    if (dmb != null)
                        d.SetValue(DragMoveBehaviorProperty, null);
                }
            },
        });

        public static bool GetIsDesignMode(FrameworkElement fe)
        {
            return (bool)fe.GetValue(DragMoveBehaviorProperty);
        }
        public static void SetIsDesignMode(FrameworkElement fe, bool value)
        {
            fe.SetValue(DragMoveBehaviorProperty, value);
        }

        private AdornerLayer _Layer = null;
        private VisualCollection _Visuals;
        private DesignFrame _Frame;

        public DesignAdorner(UIElement target)
            : base(target)
        {
            this._Visuals = new VisualCollection(this);

            #region build controls

            this._Frame = new DesignFrame { DataContext = target };
            _Visuals.Add(this._Frame);

            #endregion
        }
        public DesignAdorner(UIElement target, AdornerLayer adornerLayer)
            : this(target)
        {
            this.SetAdornerLayer(adornerLayer);
        }
        public DesignAdorner(UIElement target, bool attach)
            : this(target, AdornerLayer.GetAdornerLayer(target))
        { }

        public bool SetAdornerLayer(AdornerLayer adornerLayer)
        {
            if (this._Layer != null)
                _Layer.Remove(this);
            this._Layer = adornerLayer;
            if (this._Layer != null)
            {
                _Layer.Add(this);
                return true;
            }

            return false;
        }

        public bool SetDesignTarget(UIElement target)
        {
            _Frame.DataContext = target;
            if (target == null)
                return this.SetAdornerLayer(null);
            return this.SetAdornerLayer(AdornerLayer.GetAdornerLayer(target));
        }

        protected override int VisualChildrenCount { get { return _Visuals.Count; } }
        protected override Visual GetVisualChild(int index) { return _Visuals[index]; }

        protected override Size MeasureOverride(Size constraint)
        {
            return base.MeasureOverride(constraint);
        }
        protected override Size ArrangeOverride(Size finalSize)
        {
            // what does the fox say?
            //return base.ArrangeOverride(finalSize);

            _Frame.Arrange(new Rect(finalSize));

            return finalSize;
        }

        public static DesignAdorner AttachToElement(UIElement target)
        {
            var al = AdornerLayer.GetAdornerLayer(target);
            if (al == null) return null;

            var da = new DesignAdorner(target);
            al.Add(da);

            return da;
        }
    }
}
